package utils

// 导入所需的标准库包
import (
	"bytes"           // 导入bytes包，用于字节操作
	"encoding/base64" // 导入base64包，用于Base64编码解码
	"encoding/json"   // 导入json包，用于JSON序列化和反序列化
	"fmt"             // 导入fmt包，用于格式化输出
	"io"              // 导入io包，用于I/O操作
	"log"             // 导入log包，用于日志记录
	"net/http"        // 导入http包，用于HTTP客户端和服务器
	"time"            // 导入time包，用于时间操作
)

// Link 结构体表示一个链接，包含描述和 URL 字段
type Link struct {
	Name        string `json:"name"`        // 链接的名称
	Description string `json:"description"` // 链接的描述信息
	URL         string `json:"url"`         // 链接的 URL 地址
}

// SaveLinkViaHTTP 通过 HTTP 请求保存或更新链接信息
func SaveLinkViaHTTP(port int, name, description, url string) error {
	// 存储链接信息的切片
	var linksData []Link
	// 尝试从服务器读取现有的链接文件
	existingData, err := ReadFileViaHTTP(port, "links.json")
	// 如果读取文件失败，记录日志并继续执行
	if err != nil {
		log.Printf("Links文件[ERROR] -> 读取失败: %v", err)
	}
	// 如果成功读取到文件内容，尝试解析 JSON 数据
	if err == nil {
		// 尝试解析 JSON 数据到 linksData 切片
		var unmarshalErr error
		// 解析 JSON 数据到 linksData 切片
		if unmarshalErr = json.Unmarshal(existingData, &linksData); unmarshalErr != nil {
			// 解析失败时，清空链接数据切片
			linksData = []Link{}
			log.Printf("Links文件[ERROR] -> 解析失败: %v", unmarshalErr)
		}
	} else {
		log.Printf("Links文件[ERROR] -> 读取失败: %v", err)
	}

	// 标记是否找到匹配的链接描述
	var found = false
	// 遍历现有链接，查找匹配的描述
	for i, link := range linksData {
		if link.Name == name {
			// 找到匹配的描述，更新链接 URL
			linksData[i].URL = url
			found = true
			log.Printf("Links文件 -> 更新链接: %s -> %s", name, url)
			break
		}
	}
	// 如果未找到匹配的描述，添加新链接
	if !found {
		log.Printf("Links文件 -> 新增链接: %s -> %s", name, url)
		linksData = append(linksData, Link{
			Name:        name,
			Description: description,
			URL:         url,
		})
	}

	// 将链接数据编码为格式化的 JSON
	jsonData, err := json.MarshalIndent(linksData, "", "  ")
	if err != nil {
		return fmt.Errorf("JSON编码[ERROR] -> %v", err)
	}
	// 创建一个 HTTP POST 请求
	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf("http://localhost:%d/save", port),
		bytes.NewReader(jsonData),
	)
	if err != nil {
		return err
	}
	// 设置请求头，指定文件名（Base64 编码）
	req.Header.Set("X-File-Name", base64.StdEncoding.EncodeToString([]byte("links.json")))
	// 设置请求头，允许覆盖现有文件
	req.Header.Set("X-Overwrite", "true")
	// 设置请求头，指定内容类型为 JSON
	req.Header.Set("Content-Type", "application/json")
	// 创建 HTTP 客户端，设置超时时间为 5 秒
	client := &http.Client{Timeout: 5 * time.Second}
	// 发送 HTTP 请求
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("Links文件[ERROR] -> 请求失败: %v", err)
	}
	// 确保响应体在函数结束时关闭
	defer resp.Body.Close()
	// 检查响应状态码，如果不是 200 OK 则返回错误
	if resp.StatusCode != http.StatusOK {
		errorBody, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("Links文件[ERROR]-> %d | [REPLY]: %s", resp.StatusCode, string(errorBody))
	}
	return nil
}

// ReadFileViaHTTP 通过 HTTP 请求从服务器读取指定文件
func ReadFileViaHTTP(port int, filename string) ([]byte, error) {
	// 发送 HTTP GET 请求读取文件
	resp, err := http.Get(fmt.Sprintf("http://localhost:%d/read/%s", port, filename))
	if err != nil {
		return nil, err
	}
	// 确保响应体在函数结束时关闭
	defer resp.Body.Close()

	// 检查响应状态码，如果不是 200 OK 则返回错误
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Dev服务[ERROR] -> %d", resp.StatusCode)
	}
	// 读取响应体内容
	return io.ReadAll(resp.Body)
}
